home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Aminet 1 (Walnut Creek)
/
Aminet - June 1993 [Walnut Creek].iso
/
usenet
/
sources
/
volume89
/
languags
/
a68k242.2
< prev
next >
Wrap
Text File
|
1989-03-08
|
63KB
|
2,071 lines
Path: xanth!lll-winken!ames!mailrus!bbn!ulowell!page
From: page@swan.ulowell.edu (Bob Page)
Newsgroups: comp.sources.amiga
Subject: v89i024: a68k - 68000 assembler v2.42, Part02/04
Message-ID: <12035@swan.ulowell.edu>
Date: 8 Mar 89 01:48:29 GMT
Organization: University of Lowell, Computer Science Dept.
Lines: 2060
Approved: page@swan.ulowell.edu
Submitted-by: jlydiatt@jlami.wimsey.bc.ca (Jeff Lydiatt)
Posting-number: Volume 89, Issue 24
Archive-name: languages/a68k242.2
# This is a shell archive.
# Remove everything above and including the cut line.
# Then run the rest of the file through sh.
#----cut here-----cut here-----cut here-----cut here----#
#!/bin/sh
# shar: Shell Archiver
# Run the following text with /bin/sh to create:
# A68kmisc.c
# History.log
# A68k2do.txt
# Makefile
# Makefile.azt
# Makefile.dbg
# Makefile.pdc
# wb_parse.c
# This archive created: Tue Mar 7 20:40:28 1989
cat << \SHAR_EOF > A68kmisc.c
/*------------------------------------------------------------------*/
/* */
/* MC68000 Cross Assembler */
/* */
/* Copyright (c) 1985 by Brian R. Anderson */
/* */
/* Miscellaneous routines - January 6, 1989 */
/* */
/* This program may be copied for personal, non-commercial use */
/* only, provided that the above copyright notice is included */
/* on all copies of the source code. Copying for any other use */
/* without the consent of the author is prohibited. */
/* */
/*------------------------------------------------------------------*/
/* */
/* Originally published (in Modula-2) in */
/* Dr. Dobb's Journal, April, May, and June 1986. */
/* */
/* AmigaDOS conversion copyright 1989 by Charlie Gibbs. */
/* */
/*------------------------------------------------------------------*/
#include <stdio.h>
#include "a68kdef.h"
#include "a68kglb.h"
char Sdata[MAXSREC]; /* S-record data */
int Sindex; /* Index for Sdata */
int NumRExt, NumR32, NumR16, NumR8;
static char *errmsg[] = {
"--- Unknown error code ---",
"Alignment error.",
"No such op-code.",
"Duplicate Symbol.",
"Undefined Symbol.",
"Addressing mode not allowed here.",
"Error in operand format.",
"Error in relative branch.",
"Address mode error.",
"Operand size error.",
"END statement is missing.",
"Value must be absolute.",
"Relocatability error.",
"INCLUDE file cannot be opened.",
"Illegal forward reference.",
"Not supported in S-format.",
"This instruction needs a label.",
"Pass 1 / Pass 2 phase error.",
"ENDM statement is missing.",
"ENDC statement is missing.",
"Unmatched ENDC statement.",
"Too much DC data.",
"Too many SECTIONs.",
"Duplicate macro definition.",
"More than one label on this line.",
"End of string is missing.",
"Short displacement can't be zero.",
""};
/* Functions */
extern int LineParts(), Instructions(), ObjDir();
extern int GetInstModeSize(), GetMultReg(), CountNest();
extern int ReadSymTab(), GetArgs(), GetAReg(), OpenIncl();
extern long GetValue(), CalcValue();
extern char *AddName(), *GetField();
extern struct SymTab *NextSym();
extern struct SymTab **HashIt();
long AddrBndW(), AddrBndL();
long AddrBndW (v) register long v;
/* Advances "v" to the next word boundary */
{
register int i;
if (v & 1L) {
AppendSdata (0L, 1);
v++;
}
return (v);
}
long AddrBndL (v) register long v;
/* Advances "v" to the next long-word boundary */
{
long templong;
v = AddrBndW (v); /* Bump to a word boundary first */
if (v & 2L) { /* If still not aligned, */
templong = NOP; /* generate a NOP */
AppendSdata (templong, 2);
v += 2;
}
return (v);
}
WriteListLine (f) struct fs *f;
/* Writes one line to the Listing file, including Object Code */
{
register int i, j, printed;
long templong;
char macflag;
char tempstr[12];
int dummy;
if (!Pass2)
return; /* Pass 2 only */
if (FwdShort && (ErrLim == 0)) {
DisplayLine (dummy);
printf ("A short branch can be used here.\n");
}
if (SuppList)
return; /* Listing is suppresed */
if (ErrLim == 0)
if ((Dir == Page) || (Dir == Space) || (Dir == Title)
|| (Dir == DoList) || (Dir == NoList) || (ListOff))
return; /* Don't print unless they have errors */
CheckPage (f, FALSE); /* Print headings if necessary */
if (PrntAddr) {
if ((Dir == Equ) || (Dir == Set))
LongPut (f, ObjSrc, 3); /* Equated value */
else
LongPut (f, AddrCnt, 3); /* Current location */
if (!KeepTabs)
xputs (f, " ");
} else
if (!KeepTabs)
xputs (f, " "); /* Don't print location */
if (KeepTabs)
xputs (f, "\t"); /* Use tabs for spacing */
printed = 8; /* We've printed 8 positions */
LongPut (f, ObjOp, nO); /* Generated code */
printed += nO * 2;
if (nS != 0) {
xputs (f, " ");
LongPut (f, ObjSrc, nS);
printed += nS * 2 + 1;
}
if (nD != 0) {
xputs (f, " ");
LongPut (f, ObjDest, nD);
printed += nD * 2 + 1;
}
if ((j = nX) > 0) { /* String data */
if ((j * 2 + printed) > ObjMAX)
j = (ObjMAX - printed) / 2;
for (i = 0; i < j; i++) {
templong = ObjString[i];
LongPut (f, templong, 1);
}
printed += j * 2;
}
while (printed < ObjMAX) {
if (KeepTabs) {
xputs (f, "\t");
printed += 8;
printed &= ~7;
} else {
xputs (f, " ");
printed++;
}
}
if ((InFNum == 0) || (OuterMac == 0))
macflag = ' '; /* Open code */
else if (InFNum > OuterMac)
macflag = '+'; /* Inner macro */
else if ((InFNum == OuterMac) && (Dir != MacCall))
macflag = '+'; /* Outermost macro */
else
macflag = ' '; /* We're outside macros */
sprintf (tempstr, " %5d%c", LineCount, macflag);
xputs (f, tempstr);
xputs (f, Line);
xputs (f, "\n");
if (FwdShort && (ErrLim == 0))
xputs (f, "A short branch can be used here.\n");
for (i = 0; i < ErrLim; i++) { /* Write error messages. */
CheckPage (f, FALSE);
xputs (f, errmsg[ErrCode[i]]);
printed = strlen(errmsg[ErrCode[i]]);
while (printed < ObjMAX + 8) {
if (KeepTabs) {
xputs (f, "\t");
printed += 8;
printed &= ~7;
} else {
xputs (f, " ");
printed++;
}
}
for (j = 0; j < ErrPos[i]; j++) {
if (Line[j] == '\t') {
xputs (f, "\t");
printed += 8;
printed &= ~7;
} else {
xputs (f, " ");
printed++;
}
}
xputs (f, "^ "); /* Error flag */
if (i == 0) {
if (InF->UPtr == 0)
xputs (f, InF->NPtr); /* Module name */
else
xputs (f, "(user macro)"); /* In a user macro */
sprintf (tempstr, " line %d", InF->Line);
xputs (f, tempstr); /* Line number */
}
xputs (f, "\n");
}
}
WriteSymTab (f) struct fs *f;
/* Lists the symbol table in alphabetical order */
{
int printhunk, i;
char *p;
char tempstr[24];
long templong;
register int j, k;
register struct SymTab **ss1, **ss2, *sym, **sortlim;
struct Ref *ref;
if (NumSyms == 0)
return; /* The symbol table is empty - exit */
/* Build a sorted table of pointers to symbol table entries */
templong = NumSyms * sizeof (struct SymTab *);
SymSort = (struct SymTab **) malloc ((unsigned) templong);
if (SymSort == NULL) {
fprintf (stderr, "Not enough memory for symbol table sort!\n");
return;
}
sortlim = SymSort + NumSyms;
sym = SymChunk = SymStart;
sym++;
SymChLim = (struct SymTab *) ((char *) SymChunk + CHUNKSIZE);
ss1 = SymSort;
while (sym) {
*ss1++ = sym;
sym = NextSym (sym); /* Try for another symbol table entry */
}
for (i = NumSyms / 2; i > 0; i /= 2) { /* Shell sort */
for (ss1 = SymSort + i; ss1 < sortlim; ss1++) { /* (copied */
for (ss2=ss1-i; ss2 >= SymSort; ss2 -= i) { /* from K&R) */
if (strcmp ((*ss2)->Nam, (*(ss2+i))->Nam) <= 0)
break;
sym = *ss2;
*ss2 = *(ss2+i);
*(ss2+i) = sym;
}
}
}
/* The table is now sorted - print the listing */
LnCnt = LnMax; /* Skip to a new page. */
for (i = 0, ss1 = SymSort; i < NumSyms; i++) {
sym = *ss1++;
CheckPage (f, TRUE);
p = sym->Nam; /* Pointer to symbol */
if (sym->Flags & 8)
p++; /* Skip blank preceding macro name */
else if (sym->Flags & 0x10)
p += 6; /* Skip hunk sequence number */
sprintf (tempstr, "%-11s ", p); /* Symbol or macro name */
xputs (f, tempstr);
if (strlen (p) > 11) /* Long symbol - go to new line */
if (KeepTabs)
xputs (f, "\n\t ");
else
xputs (f, "\n ");
printhunk = FALSE; /* Assume no hunk no. to print */
if (sym->Defn == NODEF)
xputs (f, " *** UNDEFINED *** ");
else if (sym->Flags & 4)
xputs (f, " -- SET Symbol -- ");
else if (sym->Flags & 8) {
sprintf (tempstr, " +++ MACRO +++ %5d", sym->Defn);
xputs (f, tempstr);
} else if (sym->Flags & 0x10) {
j = (sym->Hunk & 0x3FFF0000L) >> 16;
if (j == HunkCode)
xputs (f, " CODE ");
else if (j == HunkData)
xputs (f, " DATA ");
else
xputs (f, " BSS ");
printhunk = TRUE;
} else if (sym->Flags & 0x20) {
sprintf (tempstr, " %c%ld ",
(sym->Val & 8L) ? 'A' : 'D', sym->Val & 7L);
xputs (f, tempstr);
printhunk = TRUE;
} else {
LongPut (f, sym->Val, 4); /* Value */
xputs (f, " ");
printhunk = TRUE;
}
if (printhunk) {
j = sym->Hunk & 0x00007FFFL; /* Hunk number */
if (sym->Flags & 0x60)
xputs (f, " Reg"); /* Register or list */
else if (sym->Flags & 1)
xputs (f, " Ext"); /* External */
else if (j == ABSHUNK)
xputs (f, " Abs"); /* Absolute */
else {
sprintf (tempstr, "%4d", j); /* Hunk number */
xputs (f, tempstr);
}
sprintf (tempstr," %5d",sym->Defn); /* Statement number */
xputs (f, tempstr);
}
if (XrefList) {
xputs (f, " ");
if (sym->Ref1 == NULL)
xputs (f, " *** UNREFERENCED ***");
else {
ref = sym->Ref1;
j = k = 0;
while (1) {
if (ref->RefNum[j] == 0)
break;
if (k >= 9) {
xputs (f, "\n"); /* New line */
if (KeepTabs)
xputs (f, "\t\t\t\t "); /* 34 spaces */
else
for (k = 0; k < 34; k++)
xputs (f, " ");
k = 0;
}
sprintf (tempstr, "%5d", ref->RefNum[j]);
xputs (f, tempstr);
j++;
k++;
if (j < MAXREF)
continue; /* Get the next slot */
if ((ref = ref->NextRef) == 0)
break; /* End of last entry */
j = 0; /* Start the next entry */
}
}
}
xputs (f, "\n");
}
free (SymSort); /* Free the sort work area */
SymSort = NULL;
}
CheckPage (f, xhdr) struct fs *f; int xhdr;
/* Checks if end of page reached yet -- if so, advances to next page. */
{
register int printed;
char tempstr[12];
LnCnt++;
if (LnCnt >= LnMax) {
PgCnt++;
if (PgCnt > 1)
xputs (f, "\f"); /* Skip to new page */
xputs (f, TTLstring); /* Title */
printed = strlen (TTLstring);
while (printed < 56)
if (KeepTabs) {
xputs (f, "\t");
printed += 8;
printed &= ~7;
} else {
xputs (f, " ");
printed++;
}
xputs (f, SourceFN); /* File name */
if (KeepTabs)
xputs (f, "\t");
else
xputs (f, " ");
sprintf(tempstr, "Page %d\n\n", PgCnt); /* Page number */
xputs (f, tempstr);
LnCnt = 2;
if (xhdr) {
xputs (f, "Symbol Value Hunk Line");
if (XrefList)
xputs (f, " References"); /* Cross-reference */
xputs (f, "\n\n");
LnCnt += 2;
}
}
}
StartSrec (f, idntname) struct fs *f; char *idntname;
/* Writes object header record */
{
register long CheckSum, templong;
register char *s;
if (SFormat) {
xputs (f, "S0");
templong = strlen (idntname) + 3; /* extra for addr. & checksum */
LongPut (f, templong, 1);
CheckSum = templong;
xputs (f, "0000"); /* Address is 4 digits, all zero, for S0 */
s = idntname;
while (*s) {
templong = toupper (*s++);
LongPut (f, templong, 1);
CheckSum += templong;
}
CheckSum = ~CheckSum; /* Complement checksum */
LongPut (f, CheckSum, 1);
xputs (f, "\n");
} else {
templong = HunkUnit;
xputl (f, templong);
DumpName (f, idntname, 0L);
}
StartAddr = TempAddr = Sindex = 0;
NumRExt = NumR32 = NumR16 = NumR8 = 0;
}
WriteSrecLine (f) struct fs *f;
/* Transfers object code components to output buffer. */
/* Moves long words or portions thereof. */
{
register int i;
register long templong;
if (HunkType == HunkBSS)
return; /* No code in BSS hunk */
if (nO + nS + nD + nX) { /* If we have object code */
AppendSdata (ObjOp, nO); /* Opcode */
AppendSdata (ObjSrc, nS); /* Source */
AppendSdata (ObjDest, nD); /* Destination */
for (i = 0; i < nX; i++) { /* String data */
templong = ObjString[i];
AppendSdata (templong, 1);
}
}
}
AppendSdata (Data, n) register long Data; int n;
/* If we are producing S-format records:
Transfers "n" low-order bytes from "Data" to the output buffer.
If the buffer becomes full, DumpSdata will be called to flush it.
S-records will also be broken on 16-byte boundaries.
If we are producing AmigaDOS format, data will be written
directly to Srec - we'll go back and fill in the hunk length
at the end of the hunk. DumpSdata will never be called from here. */
{
register int i;
register char byte;
int dummy;
if (!Pass2)
return; /* Pass 2 only */
if (HunkType == HunkBSS)
return; /* No data in BSS hunks! */
if (HunkType == HunkNone) { /* We're not in a hunk yet - */
DoSection ("", 0, "", 0, "", 0); /* start a code hunk */
MakeHunk = TRUE;
}
if (OrgFlag) { /* If we've had an ORG directive */
FixOrg (dummy); /* do necessary adjustments */
OrgFlag = FALSE; /* to the object code file. */
}
Data <<= (4 - n) * 8; /* Left-justify data */
for (i = 0; i < n; i++) {
byte = (char) (Data >> ((3 - i) * 8));
TempAddr++;
if (!SFormat) {
xputc (byte, &Srec);
} else {
Sdata[Sindex++] = byte;
if (((TempAddr & 0x0F) == 0) || (Sindex >= MAXSREC))
DumpSdata (&Srec); /* Break S-record */
}
}
}
FixOrg (dummy) int dummy;
/* Makes necessary adjustments to the object code file if an
ORG directive has been processed. This routine is called
exclusively by AppendSdata and must only be called once for
each ORG encountered, when writing the next object code (if any). */
{
register long templong;
register int i;
if (SFormat && (AddrCnt != TempAddr)) { /* ORG in S-format - */
DumpSdata (&Srec); /* dump current record */
StartAddr = TempAddr = AddrCnt; /* and start afresh. */
}
if (AddrCnt < TempAddr) { /* AmigaDOS backward ORG */
if (TempAddr > OrgHigh) {
LenPtr = NULL;
OrgHigh = TempAddr; /* Save high address for return */
if (Srec.Ptr > Srec.Buf) /* Flush the buffer */
write (Srec.fd, Srec.Buf, Srec.Ptr - Srec.Buf);
OrgSeek = lseek (Srec.fd, 0L, 1); /* Remember position */
lseek (Srec.fd,(AddrCnt & ~3L)-TempAddr,1); /* New position */
if (AddrCnt & 3L) { /* If ORG isn't to long-word */
read (Srec.fd, Srec.Buf, AddrCnt & 3L); /* move ahead */
lseek (Srec.fd, -(AddrCnt & 3L), 1); /* to keep */
} /* the buffer */
Srec.Ptr = Srec.Buf + (AddrCnt & 3L); /* aligned. */
}
StartAddr = TempAddr = AddrCnt;
} else if (AddrCnt > TempAddr) { /* AmigaDOS forward ORG */
if (OrgHigh > TempAddr) { /* Previous backward ORG */
if (AddrCnt < OrgHigh)
templong = AddrCnt; /* Within previous range */
else
templong = OrgHigh; /* Beyond previous range */
i = (int) (templong & 3L); /* Alignment factor */
templong -= TempAddr; /* Number of bytes to skip */
LenPtr = NULL;
if (Srec.Ptr > Srec.Buf) /* Flush the buffer */
write (Srec.fd, Srec.Buf, Srec.Ptr - Srec.Buf);
lseek (Srec.fd,templong-(long)i,1); /* Skip written data */
if (i) { /* If skip isn't to long-word, */
read(Srec.fd,Srec.Buf,(long)i); /* move ahead */
lseek(Srec.fd, -((long) i), 1); /* to keep */
} /* the buffer */
Srec.Ptr = Srec.Buf + (long) i; /* aligned. */
TempAddr += templong;
StartAddr = TempAddr;
}
while (TempAddr < AddrCnt) { /* Extend with binary zeros */
xputc (0, &Srec);
TempAddr++;
}
}
}
DumpSdata (f) register struct fs *f;
/* Writes an object code record */
{
register long CheckSum, templong;
register char *s;
register int i;
if (!SFormat) {
if (AddrCnt < OrgHigh) { /* If we did a backwards ORG */
LenPtr = NULL; /* we have to fix things up */
if (f->Ptr > f->Buf) /* Flush the buffer */
write (f->fd, f->Buf, f->Ptr - f->Buf);
lseek(f->fd,OrgSeek&~3L,0); /* Back to high position */
if (OrgSeek & 3L) { /* If ORG isn't to long-word, */
read (f->fd, f->Buf, OrgSeek & 3L); /* move ahead */
lseek (f->fd, -(OrgSeek & 3L), 1); /* to keep */
} /* the buffer */
f->Ptr = f->Buf + (OrgSeek & 3L); /* aligned. */
AddrCnt = StartAddr = TempAddr = OrgHigh;
}
AddrCnt = AddrBndL (AddrCnt); /* Finish the last long word */
templong = ((AddrCnt - SectStart) >> 2) | HunkFlags;
if ((s = LenPtr) == NULL) {
if (f->Ptr > f->Buf) /* Flush the buffer */
write (f->fd, f->Buf, f->Ptr - f->Buf);
CheckSum = lseek (f->fd, 0L, 1); /* Remember position */
lseek (f->fd, LenPos, 0); /* Put hunk length here */
s = f->Buf;
}
*s++ = (char) (templong >> 24);
*s++ = (char) (templong >> 16);
*s++ = (char) (templong >> 8);
*s++ = (char) templong;
if (LenPtr == NULL) {
write (f->fd, f->Buf, 4);
lseek (f->fd, CheckSum, 0); /* Back to where we were */
f->Ptr = f->Buf;
}
DumpRel (f); /* Write relocation information */
templong = HunkEnd;
xputl (f, templong); /* End of the hunk */
TempAddr = AddrCnt;
return;
}
if (Sindex == 0)
return; /* There's nothing to dump */
xputs (f, "S2");
templong = Sindex + 4; /* Record length */
LongPut (f, templong, 1);
CheckSum = templong; /* Initialize CheckSum */
LongPut (f, StartAddr, 3); /* Address */
CheckSum += (StartAddr >> 16) & 0x00FFL;
CheckSum += (StartAddr >> 8) & 0x00FFL;
CheckSum += StartAddr & 0x00FFL;
for (i = 0; i < Sindex; i++) {
templong = Sdata[i];
LongPut (f, templong, 1); /* Object code */
CheckSum += templong;
}
CheckSum = ~CheckSum; /* Complement checksum */
LongPut (f, CheckSum, 1);
xputs (f, "\n");
StartAddr += Sindex;
TempAddr = StartAddr;
Sindex = 0;
}
PutRel (addr, hunk, size) long addr, hunk; int size;
/* Build a relocation entry if necessary */
{
register struct RelTab *rel;
if (!Pass2)
return; /* Pass 2 only */
if (SFormat)
return; /* Not for S-format! */
if (hunk == ABSHUNK)
return; /* Absolute */
if (HunkType == HunkBSS)
return; /* Not for BSS hunks! */
rel = RelLim; /* Pointer to new entry */
RelLim++; /* Bump limit pointer */
if (((char *) RelLim - (char *) RelCurr) > CHUNKSIZE) {
rel = (struct RelTab *) malloc ((unsigned) CHUNKSIZE);
if (rel == NULL)
quit_cleanup ("Out of memory!\n");
RelCurr->Link = rel; /* Link from previous chunk */
RelCurr = rel; /* Make the new chunk current */
RelCurr->Link = NULL; /* Clear forward pointer */
rel++; /* Skip over pointer entry */
RelLim = rel; /* New table limit */
RelLim++; /* Bump it */
}
if (RelLast != NULL)
RelLast->Link = rel; /* Link from previous entry */
rel->Link = NULL; /* End of the chain (so far) */
rel->Offset = addr; /* Offset */
rel->Hunk = hunk; /* Hunk number */
rel->Size = size; /* Size */
RelLast = rel; /* Pointer to last entry in chain */
if (hunk < 0) /* Count entries by type */
NumRExt++;
else if (size == Long)
NumR32++;
else if (size == Word)
NumR16++;
else
NumR8++;
}
DumpRel (f) struct fs *f;
/* Dump relocation information to the object file. */
{
register struct SymTab *sym;
register struct RelTab *rel, *rel2;
int i, j, size, num, donexhdr, secthlin;
long currhunk, nexthunk, templong;
char *p;
secthlin = LineCount; /* Current section ends here */
if ((Dir == Section) /* unless we're starting */
|| (Dir == CSeg) /* a new section. */
|| (Dir == DSeg)
|| (Dir == BSS))
secthlin--; /* Then it ends at previous line */
if (SFormat)
return; /* S-format is absolute! */
while (1) {
if ((num = NumR32) != 0) {
size = Long; /* Do 32-bit fields */
templong = HunkR32;
NumR32 = 0; /* ...but only once */
} else if ((num = NumR16) != 0) {
size = Word; /* Then do 16-bit fields */
templong = HunkR16;
NumR16 = 0;
} else if ((num = NumR8) != 0) {
size = Byte; /* Finally do 8-bit fields */
templong = HunkR8;
NumR8 = 0;
} else
break; /* We're all done */
xputl (f, templong); /* Record type */
currhunk = 32767;
num = 0;
if (rel = RelStart) /* If we have anything, */
rel++; /* skip over the first chunk's link. */
while (rel) {
if ((rel->Size == size) && (rel->Hunk >= 0)) {
if (rel->Hunk < currhunk) {
currhunk = rel->Hunk; /* Lowest hunk number */
num = 1; /* Reset counter */
} else if (rel->Hunk == currhunk) {
num++; /* Count entries */
}
}
rel = rel->Link;
}
while (num > 0) { /* Repeat for all hunk references */
templong = num;
xputl (f, templong); /* Number of entries */
xputl (f, currhunk); /* Hunk number */
nexthunk = 32767;
num = 0; /* Count for next hunk */
if (rel = RelStart)
rel++;
while (rel) {
if ((rel->Size == size) && (rel->Hunk >= 0)) {
if (rel->Hunk < currhunk) {
rel = rel->Link; /* Already wrote it */
continue;
} else if (rel->Hunk == currhunk) {
xputl (f, rel->Offset - SectStart);
} else if (rel->Hunk < nexthunk) {
nexthunk = rel->Hunk; /* Next hunk number */
num = 1; /* Reset counter */
} else if (rel->Hunk == nexthunk) {
num++; /* Count entries */
}
}
rel = rel->Link;
}
currhunk = nexthunk; /* Get ready for next hunk */
}
xputl (f, 0L); /* End of relocation information */
}
donexhdr = FALSE; /* Haven't written hunk_ext yet */
sym = SymChunk = SymStart;
sym++;
SymChLim = (struct SymTab *) ((char *) SymChunk + CHUNKSIZE);
while (sym) {
if (sym->Flags & 2) { /* Scan for XDEF symbols */
j = sym->Defn; /* Defined in current section? */
if ((j >= SectLine) && (j <= secthlin)) {
if (!donexhdr) {
templong = HunkExt; /* Haven't done header yet */
xputl (f, templong);
donexhdr = TRUE;
}
if ((sym->Hunk & 0x0000FFFFL) == ABSHUNK)
templong = 0x02000000;
else
templong = 0x01000000; /* Flags */
DumpName (f, sym->Nam, templong); /* Symbol */
xputl (f, sym->Val - SectStart); /* Offset */
}
}
sym = NextSym (sym);
}
if (NumRExt != 0) { /* External references (XREF) */
if (!donexhdr) {
templong = HunkExt; /* Haven't done header yet */
xputl (f, templong);
donexhdr = TRUE;
}
if (rel = RelStart)
rel++;
while (rel) {
if (rel->Hunk < 0) {
p = (char *) ~(rel->Hunk);
size = rel->Size;
if (size == Long)
templong = 0x81000000L; /* ext_ref32 */
else if (size == Word)
templong = 0x83000000L; /* ext_ref16 */
else
templong = 0x84000000L; /* ext_ref8 */
DumpName (f, p, templong); /* Flags and symbol */
templong = 1;
rel2 = rel->Link;
while (rel2) {
if ((rel2->Hunk == rel->Hunk) && (rel2->Size == size))
templong++; /* Number of times */
rel2 = rel2->Link; /* symbol occurs */
}
xputl (f, templong);
rel2 = rel; /* Now go back and */
while (rel2) { /* write them out. */
if ((rel2->Hunk==rel->Hunk) && (rel2->Size==size)) {
xputl(f, rel2->Offset - SectStart); /* Offset */
if (rel2 != rel) /* Kill hunk so we */
rel2->Hunk = 0; /* don't do it again */
} /* (we're done with */
rel2 = rel2->Link; /* the table anyway) */
}
}
rel = rel->Link;
}
NumRExt = 0;
}
if (donexhdr)
xputl (f, 0L); /* End of external information */
if (DumpSym) { /* Dump the symbol table */
donexhdr = FALSE;
sym = SymChunk = SymStart;
sym++;
SymChLim = (struct SymTab *) ((char *) SymChunk + CHUNKSIZE);
while (sym) {
if ((sym->Hunk & 0x0000FFFFL) == CurrHunk) {
j = sym->Flags & 0x7F; /* Ignore PUBLIC flag */
if ((j == 0) || (j == 2)) { /* Defined, may be XDEF */
if ((sym->Defn >= SectLine) && (sym->Defn <= secthlin)) {
if (!donexhdr) { /* In current SECTION */
templong = HunkSym;
xputl (f, templong); /* Write header */
donexhdr = TRUE; /* if necessary */
}
DumpName (f, sym->Nam, 0L); /* Symbol */
xputl(f, sym->Val - SectStart); /* Offset */
}
}
}
sym = NextSym (sym);
}
if (donexhdr)
xputl (f, 0L); /* End of symbol table dump */
}
rel = RelStart->Link;
while (rel != NULL) {
rel2 = rel;
rel = rel2->Link;
free (rel2); /* Free all but the first chunk */
}
RelCurr = RelStart; /* The first chunk is current */
RelCurr->Link = NULL; /* Unlink additional chunks */
RelLast = NULL; /* There are no entries left */
RelLim = RelStart;
RelLim++; /* First unused space */
}
EndSdata (f, addr) struct fs *f; long addr;
/* Write end record to object file */
{
register long checksum, templong;
if (SFormat) {
DumpSdata (f); /* Write any remaining data */
xputs (f, "S804"); /* Record header */
checksum = 4;
LongPut (f, addr, 3); /* Transfer address */
checksum += (addr >> 16) & 0x00FFL;
checksum += (addr >> 8) & 0x00FFL;
checksum += addr & 0x00FFL;
checksum = ~checksum;
LongPut (f, checksum, 1); /* Checksum */
xputs (f, "\n");
} else {
if (HunkType != HunkNone) {
DumpSdata (f); /* Last hunk's data */
}
}
}
DumpName (f, name, flags) struct fs *f; char *name; long flags;
/* Writes a name preceded by a long word containing the
length of the name in long words. The length word has
the contents of "flags" ORed into it. The name is padded
with binary zeros to the next long word boundary. */
{
register int i;
register long templong;
i = strlen (name);
templong = (i + 3) >> 2; /* Length of name (long words) */
templong |= flags; /* Add flag bits */
xputl (f, templong); /* Write length and flags */
xputs (f, name); /* Write the name itself */
while (i & 3) {
xputc ('\0', f); /* Pad the last word */
i++;
}
}
LongPut (f, data, length) struct fs *f; long data; int length;
/* Writes to file "f" the hexadecimal interpretation of
the bytes in "data". The number of bytes written
(two hex digits per byte) is given in "length" -
if less than 4, only low-order bytes are written. */
{
register int i, j;
register char *t;
char xstr[9];
t = xstr;
for (i = length * 8 - 4; i >= 0; i -= 4) {
j = (int) ((data >> i) & 0x0FL);
*t++ = (char) ((j > 9) ? (j - 10 + 'A') : (j + '0'));
}
*t = '\0';
xputs (f, xstr);
}
xopen (name, f, desc) char *name; struct fs *f; char *desc;
/* Opens the output file whose name is in "name",
setting up the file structure pointed to by "f".
This routine first allocates a file buffer -
if unsuccessful, it calls quit_cleanup.
Otherwise, it opens the file - if unsuccessful,
displays an error message using "desc" and returns TRUE.
If the file is successfully opened, this routine returns FALSE. */
{
if ((f->Buf = (char *) malloc (BUFFSIZE)) == NULL)
quit_cleanup ("Out of memory!\n");
if ((f->fd = creat (name, 1)) == -1) {
fprintf (stderr, "Unable to open %s file.\n", desc);
f->fd = NULL;
return (TRUE);
}
f->Ptr = f->Buf;
f->Lim = f->Buf + BUFFSIZE;
return (FALSE);
}
xputs (f, s) struct fs *f; register char *s;
/* Writes the string pointed to by "s"
to the output file whose structure is pointed to by "f". */
{
register char *t, *l;
t = f->Ptr; /* Current position (use registers for speed) */
l = f->Lim; /* End of buffer */
while (*s) {
*t++ = *s++;
if (t >= l) {
write (f->fd, f->Buf, t - f->Buf); /* Flush the buffer */
if (f == &Srec)
LenPtr = NULL; /* Hunk length is no longer in buffer */
t = f->Buf; /* Reset pointer */
}
}
f->Ptr = t; /* Update pointer */
}
xputl (f, data) register struct fs *f; register long data;
/* Writes to file "f" the contents of the long word in "data". */
{
xputc ((char) (data >> 24), f);
xputc ((char) (data >> 16), f);
xputc ((char) (data >> 8), f);
xputc ((char) data, f);
}
xputc (byte, f) char byte; register struct fs *f;
/* Writes the byte contained in "byte" to file "f". */
{
register char *t;
t = f->Ptr; /* Current position (use register for speed) */
*t++ = byte;
if (t >= f->Lim) {
write (f->fd, f->Buf, t - f->Buf); /* Flush the buffer */
if (f == &Srec)
LenPtr = NULL; /* Hunk length is no longer in buffer */
t = f->Buf; /* Reset pointer */
}
f->Ptr = t; /* Update pointer */
}
xclose (f) struct fs *f;
/* Closes the output file whose structure is pointed to by "f".
The buffer is flushed if necessary, then freed. */
{
if (f->Ptr > f->Buf)
write (f->fd, f->Buf, f->Ptr - f->Buf); /* Flush the buffer */
close (f->fd); /* Close the file */
f->fd = NULL;
free (f->Buf); /* Free the buffer */
f->Buf = NULL;
}
Error (pos, errornum) int pos, errornum;
/* Displays error message #errornum. If this is the first error for
the current line, the line itself is displayed, preceded by a
message giving the current position in the current module.
If the line is in a macro or include file, the position in
each nested module is given, working out to the source file.
A flag is placed under the column indicated by "pos". */
{
register int i;
int dummy;
if (!Pass2 && (errornum != NoIncl)) {
if (IncStart != 0) { /* Don't skip this */
IncStart = 0; /* INCLUDE file in */
if (SkipLim->Set1 != NULL) { /* pass 2 - we must */
SetFixLim = SkipLim->Set1; /* re-read it to */
SetFixLim++; /* report its errors. */
}
}
return; /* Report during pass 2 only */
}
if (ErrLim < ERRMAX) { /* Save error data */
ErrCode[ErrLim] = errornum;
ErrPos[ErrLim] = pos;
ErrLim++;
}
if (ErrLim == 1) /* If first error for this line */
DisplayLine (dummy); /* display the line and its number(s) */
printf ("\t");
for (i = 0; i < pos; i++)
if (Line[i] == '\t')
printf ("\t");
else
printf(" "); /* Space over to error column */
printf ("^ %s\n",errmsg[errornum]); /* Error flag and message */
ErrorCount++; /* Count errors */
}
DisplayLine (dummy) int dummy;
/* Displays the current line and its position
in all current files - used by Error, etc. */
{
register struct InFCtl *inf;
register int i;
printf ("\n");
for (i = InFNum, inf = InF; i >= 0; i--, inf++) { /* Nested? */
if (inf->UPtr == 0)
printf ("%s", inf->NPtr); /* Module name */
else
printf ("(user macro)"); /* In a user macro */
printf (" line %d\n", inf->Line); /* Line number in module */
}
printf ("%5d %s\n", LineCount, Line); /* The line itself */
}
SHAR_EOF
cat << \SHAR_EOF > History.log
A 6 8 K M A I N T E N A N C E H I S T O R Y
Version 2.42 (Charlie Gibbs, January 10, 1989)
The following bugs in version 2.41 have been corrected:
- Small code/data conversion was sometimes taking place
when no NEAR directive was active. (Jeff Lydiatt)
Version 2.41 (Charlie Gibbs, January 6, 1989)
The following bugs in version 2.4 have been corrected:
- The second operand of LINK instructions was
being erroneously flagged.
- If a macro was used before it was defined, it
was being expanded during pass 2 but not during
pass 1, causing severe phase errors. Attempts
to use a macro before it is defined will now
be flagged as invalid opcodes. (Colin Fox)
Version 2.4 (Charlie Gibbs, January 4, 1989)
The following bugs in version 2.31 have been corrected:
- If comments immediately followed the operands of
a DC statement with no intervening white space,
A68k would hang. (Ulf Nordquist)
- In the following command:
a68k -w 15000 myprog.asm
the space between the -w and 15000 would cause A68k
to look for a source file called "15000", and to think
that the object file is to be called "myprog.asm".
When it can't find "15000" it would display an error
message and scratch "myprog.asm". (Jeff Lydiatt)
- If an INCLUDE file that is skipped on pass 2 contains
a macro calls, subsequent uses of \@ (macro sequence
number are subsequently flagged. The macro counter
must be bumped along with the line number when
skipping an INCLUDE. (Colin Fox, Harvey Taylor)
The following enhancements have been added:
- ORG and RORG are now fully implemented.
- The SET symbols A68k, a68K, and a68k are defined in the
same way as A68K, making it effectively case-insensitive.
(Colin Fox)
- MOVEM and REG now accept equated register names (EQUR)
in register lists. (Bruce Dawson)
- INCLUDE files will now be skipped on pass 2 even when
a listing file is requested, if the listing has been
turned off by a NOLIST directive before the INCLUDE,
and is not turned on until after the end of the
INCLUDE file has been reached. (Colin Fox)
- A new switch (-f) causes forward branches (Bcc, BRA, BSR)
that could be coded as short branches (Bcc.S etc.) to be
flagged. This flag is not considered to be an error.
- A limited small code / small data model has been provided.
It is activated by a NEAR directive in the code, and is
de-activated by a FAR directive. External variables must
be declared at the beginning of the program, which must
consist of only two sections (CODE and DATA or BSS).
All forward data references are assumed to be PC-relative
if in the CODE section, A4-relative if in the DATA/BSS
section, and absolute word if absolute values. Any
forward references which cannot be resolved to one of
these three in pass 2 will be flagged as errors, as will
any attempt to define more than two sections. A4 is
assumed to point to the start of the DATA/BSS section
plus 32768 bytes, and must be loaded by a MOVE.L
instruction using immediate mode unless this instruction
is not enclosed within NEAR and FAR directives.
- Miscellaneous optimizations, for speed, including:
Most of the object code generator in pass 1 is bypassed.
If GetValue gets a single term it takes a short cut.
IsOperator now uses a table look-up.
Instructions now only searches that portion of the
opcode table whose opcodes start with the same letter
as the OpCode being searched for.
Version 2.31 (Charlie Gibbs, November 30, 1988)
The following bugs in version 2.3 have been corrected:
- Even though a macro definition was being skipped
by IFxx/ENDC, its ENDM directive was still being
detected, causing spurious diagnostics. (Harvey Taylor)
- NOP was not being recognized. When moving all
directives into the opcode table, NOL and NOLIST
were placed after NOP, rather than before. (Colin Fox)
- Symbols defined in the current module and declared
as PUBLIC were not being written to the object code
file when -d was specified. (Colin Fox)
- Conversion of 0(An) to (An) (implemented in version
1.2) was causing errors in the MOVEP instruction,
which requires a displacement even if it is zero.
This conversion is now disabled for MOVEP instructions.
- User macros containing invalid opcodes caused A68k
to get lost when returning to the outer source file.
(Colin Fox)
- Large values of -w (over 6000 or so) would cause
a visit from the Guru. The work field in HashIt
was overflowing and going negative. Changing it
to unsigned corrected the problem. (Colin Fox)
- Although user macros are no longer displayed when
-q is a negative number, the calling file's name
was still being displayed at the end of the macro.
Version 2.3 (Charlie Gibbs, November 21, 1988)
The following enhancements have been added:
- All file I/O has been rewritten to use level 1 I/O
(open, creat, close, read, write, and lseek) instead
of level 2 I/O. A68k now does its own buffering and
unbuffering to reduce system overhead and increase speed.
(Bruce Dawson)
- All assembler directives have been incorporated into
the opcode table. Since the opcode search now looks
up directives as well, speed is increased.
- Miscellaneous code optimization for additional speed.
Version 2.2 (Charlie Gibbs, November 4, 1988)
The following bugs in version 2.1 have been corrected:
- Macro definitions within an INCLUDE file were
disabling the test for skipping the file on pass 2.
- Errors encountered in an INCLUDE file on pass 1
were not disabling the skip of the file on pass 2 -
the pertinent error messages could not appear.
- XDEF information and optional symbol table dumps were
not being written to the object code file for any
hunks that did not contain relocatable code or data.
(Colin Fox)
The following enhancements have been added:
- If the -q option is specified as a negative value,
user macros are no longer included in line number
displays, reducing clutter.
- Some source code has been re-arranged to reduce size.
Version 2.1 (Charlie Gibbs, November 1, 1988)
The following bugs in version 2.00 have been corrected:
- Macro definitions that span two chunks of memory
were causing garbage and probably a crash when
the macro was being expanded. Pointers were not
being handled properly when linking the two chunks.
- Statements such as EQU and SET were not being flagged
as illegal forward references if referencing a label
defined on the same line, e.g.
LABEL SET LABEL+1
- The position within macros and INCLUDE files was
sometimes out by one line when reported in error
messages (and the new feature of the -q switch).
The following enhancements have been added:
- If the -q option is specified as a negative value,
line numbers will be displayed as positions within
the current module (whose name is also displayed),
rather than a total statement count. (Bruce Dawson)
- INCLUDE files can be skipped on pass 2 even if they
contain SET statements - the values of all symbols
SET in the INCLUDE file are stored (as at the end
of the file) in a separate table and are patched
when the INCLUDE file is skipped. (Bruce Dawson)
Version 2.00 (Charlie Gibbs, October 26, 1988)
The following bugs in version 1.24 have been corrected:
- The last digit of the statement number display
(lengthened in version 1.24) was not being erased
before displaying error messages.
- A68k would go into a loop if a user macro was
missing an ENDC directive. This error is now
flagged (see below).
The following enhancements have been added:
- The highest statement number displayed at the end of
each pass is now left on the screen. This means that,
at the end of pass 1, you can always see how many lines
A68k will have to process in pass 2, giving an idea of
how how much longer you have to wait. (Colin Fox)
- The symbol table is now built using a hashing algorithm.
This eliminates the slowdown that occurs in pass 1 as
the symbol table grows, due to the old insertion process.
(Bruce Dawson)
- If A68k terminates abnormally for any reason (such as
insufficient memory) the object file is scratched
(unless the -k option is set). (Bruce Dawson)
- Any INCLUDE files which cannot be found are flagged
as errors in pass 1, and the assembly is aborted
at the end of pass 1. (Bruce Dawson)
- Missing ENDC directives are flagged in macro expansions.
Also, missing or unpaired ENDC directives in user macros
are flagged.
- If an INCLUDE file doesn't generate any code and no
listing file is required, it won't be read again in
pass 2. The statement numbers will be bumped to keep
in proper alignment. This can really speed up
assemblies that INCLUDE lots of equates. (Colin Fox)
Version 1.24 (Charlie Gibbs, October 11, 1988)
The following bugs in version 1.23 have been corrected:
- MOVEA to a data register was not being flagged, even
though all other invalid addressing modes were.
- Attempts to ORG out of the current hunk (including
to an absolute address) were not being flagged. (E. Lenz)
- If the size of the bottom of the primary heap (symbols
and macro text) exceeded 32K, any further macro
definitions would expand as endless garbage. (Colin Fox)
- If the size of the bottom of the primary heap (symbols
and macro text) exceeded 64K, any further external
symbols (XDEF) would be flagged as relocatability
errors upon each reference. (Colin Fox)
The following enhancements have been added:
- Where statement numbers are displayed as fixed-length
fields, their maximum length has been increased
from 4 digits to 5. (Colin Fox)
- The PUBLIC directive has been implemented.
As with the Aztec assembler, any labels defined as
PUBLIC will be treated as XDEF if defined within
the current module, and XREF otherwise. (Jeff Lydiatt)
Version 1.23 (Charlie Gibbs, September 20, 1988)
The following bugs in version 1.22 have been corrected:
- The test for a third operand was producing erroneous
error messages on instructions whose second operand
was in immediate mode. The '#' was not being taken
into account, since it is not copied to DestOp.
Version 1.22 (Charlie Gibbs, August 31, 1988)
The following bugs in version 1.21 have been corrected:
- Expressions of the form R-A, where R is a relocatable
term or expression and A is an absolute term or
expression, were being flagged as relocation errors.
This was due to a bug in the routine which should
(but did not) flag expressions of the form A-R.
(David Ashley)
- Instructions with three operands were not being
flagged as errors. This can be caused by an extra
comma being typed in the instruction, as in:
BTST #0,state+3,(a5)
The second comma should not be present. (David Ashley)
The following enhancements have been added:
- Excess spacing has been removed from the listing file.
These changes are similar to those already made to the
console output (probably at about version 1.05).
- If the first statement in the source file is TTL or
PAGE, an empty page is no longer produced at the
start of the listing.
Version 1.21 (Charlie Gibbs, July 29, 1988)
The following bugs in version 1.2 have been corrected:
- The instruction
BTST.L #8,D0
had a long-word value generated for the bit number.
This bug also applies to BSET, BCLR, and BCHG.
The .L specification is now ignored. (Ulf Nordquist)
Version 1.2 (Charlie Gibbs, July 19, 1988)
The following bugs in version 1.12 have been corrected:
- A reference to the label of the current instruction
was being converted to PC-relative on pass 2 but not
on pass 1. This was causing phase errors. The label
hasn't been added to the symbol table at the time the
instruction is processed. Conversion to PC-relative
addressing will now not be attempted in this case,
although references to * can and will be converted.
- All string-type DC statements, regardless of length,
were being treated as DC.B. For example, DC.L 'A'
would generate only one byte of object code.
(Gerald Hull)
- DC.W and DC.B statements were not being checked to
ensure that their values would fit into a word or
a byte respectively.
- If a comment line had white space preceding the
asterisk, A68k would hang. Actually, it was
interpreting the asterisk as an opcode and trying
to open a macro file called "*". Since under
AmigaDOS such a file is the console, A68k was
actually waiting for console input.
- If an instruction with no operands (such as RTS
or NOP) followed MOVE.L #rel,D0 where "rel" was
a relocatable symbol, the RTS (etc.) would have
its nonexistent operands flagged as invalid.
- SECTION names enclosed in quotes were not being
handled correctly.
- Source modules that did not generate any code, data,
or BSS areas, but only defined symbols, such as
label equ 4
xdef label
end
were generating incomplete object modules.
The following enhancements have been added:
- Jeff's experimental hunk code (prefixing hunk names
with a sequence number before adding to the symbol
table) has been permanently incorporated. It seems
to work better with BLink on programs that have
hunks continued farther on in the source code.
(Jeff Lydiatt)
- The macro parameter \0, which is replaced by the
size specification in the macro call (B, W, or L,
defaulting to W) is now supported. (Gerald Hull)
- Operands of the form 0(An) will be treated as (An).
(Bruce Dawson)
Version 1.12 (Charlie Gibbs, May 25, 1988)
The following bugs in version 1.11 have been corrected:
- If an instruction with no operands (e.g. RTS)
followed a MOVE.L #label,D0 the RTS would be
flagged with a relocatability error. Src.Mode
and Dest.Mode were not being cleared. (Colin Fox)
Version 1.11 (Charlie Gibbs, April 6, 1988)
The following bugs in version 1.10 have been corrected:
- A68k would go into a loop while processing the
arguments of a macro call, if these arguments are
followed by comments separated from the arguments
by one or more tab characters, and the -t switch
is specified on the command line. All tests for
blanks have been replaced by calls to isspace().
- The operand alignment checks added in version 1.06
were erroneously testing the following instructions:
BCHG
BCLR
BSET
BTST
NBCD
Scc
TAS
These instructions are now exempt from alignment checking.
The following enhancements have been added:
- A listing file name can now be specified with the
-x switch; it is no longer necessary to specify
both the -l and -x switches to produce a cross-
reference listing with a name other than the default.
- DS statements with more than one operand are
flagged and ignored (in case they should be DC).
- A character string used as a numeric value is
flagged and set to zero if it is more than four
characters long.
Version 1.10 (Charlie Gibbs, March 20, 1988)
The following bugs in version 1.07 have been corrected:
- BSS sections were not being written to the object
code file except for a BSS section at the end of
a program. This is due to a bug in the code added
in version 1.05 to overwrite null sections.
- If a source module contained a mixture of lengths
(8, 16, or 32 bits) in external references (XREF)
to the same label, all references were being treated
as if they has the length of the first reference.
The following enhancements have been added:
- DS operands that are either a forward references
or relocatable are now flagged.
- Short branches (Bcc.S, including BRA and BSR) to
the next instruction (i.e. a displacement of zero)
are illegal - the processor takes the displacement
from the next word. Attempts to generate a short
displacement of zero are now flagged.
Version 1.07 (Charlie Gibbs, March 11, 1988)
The following bugs in version 1.06 have been corrected:
- Instructions that take no operands (such as RTS)
were being flagged if they had comments that were
not preceded by a semicolon.
The following enhancements have been added:
- The following synonyms have been added:
CSEG for CODE (Aztec compatibility)
DSEG for DATA " "
ENDIF for ENDC (Assempro compatibility)
= for EQU " "
| for ! " "
- Strings and character values may be delimited by
either apostrophes (') or quotation marks (").
The character not used as a delimiter can be used
within the string without doubling it. For example,
DC.B "This is Charlie's assembler"
produces the same code as
DC.B 'This is Charlie''s assembler"
- The object code file will be scratched if any errors
were found, unless the -k (keep) flag is set.
(Bruce Dawson)
- The symbol .A68K is automatically defined at the
beginning of each assembly as a SET symbol with an
absolute value of 1. This enables programs to check
whether they're being assembled by this assembler.
(Jeff Lydiatt)
- The symbol table insertion routine has been
greatly speeded up.
Version 1.06 (Charlie Gibbs, March 6, 1988)
The following bugs in version 1.05 have been corrected:
- Lines skipped by IFxx/ENDC were not being counted
in the line number given in error messages.
- DATA and BSS sections may be unnamed, or have names
the same as CODE sections. Honest, I thought section
names had to be unique even across types.
- CHIP and FAST options on the CODE, DATA, and BSS
synonyms for the SECTION directive were not being
handled correctly.
- XDEF records and symbol table records (if desired)
were not being produced for symbols defined ahead
of the first object-code producing instruction.
The following enhancements have been added:
- The CNOP instruction can now force alignment
relative to any boundary up to 128 bytes.
The second operand must still be a power of 2.
- The -q switch has been added to change the frequency
with which progress reports (current line number) are
displayed on the console. The default remains at
every 10 lines (-q10). If you specify -q (no interval)
or -q0 the line number displays will be suppressed.
This will make assemblies run slightly faster due to
reduced console I/O. (Bill Henning)
- The -t switch has been added to keep any tabs in the
source file when producing the listing file, as well as
generating tabs elsewhere whenever possible. This
speeds up assemblies and gives smaller listing files,
but such listing files cannot be displayed on devices
that do not assume a tab stop in every 8th position.
(Bruce Dawson)
- Any single-operand instruction with two operands,
and any no-operand instruction with any operands,
will be flagged.
- Relocatable 8- or 16-bit immediate operands
will be flagged. They blow up BLink.
- Named local labels are now supported. Their names
are formed in the same way as normal labels, but are
then preceded by a backslash. Their scope is the
same as normal local labels (nnn$). (Colin Fox)
- An alignment error will be flagged in the following cases:
Odd displacement on a LINK instruction
Bcc or DBcc to an odd address
In any word or long-word instruction, any operand
using the following addressing modes:
Address register indirect with displacement
Address register indirect with index and displacement
Absolute short
Absolute long
Program counter indirect with displacement
Program counter indirect with index and displacement
LEA and PEA instructions are exempt from these tests.
- If a section is found to contain no data, A68k will
back up to its beginning and overwrite it with the
next section. The result is that null sections
will no longer appear in the object file.
Version 1.05 (Charlie Gibbs, October 30, 1987)
The following bugs in version 1.04 have been corrected:
- If a section was continued later in the program, e.g.
SECTION prog,CODE
<code>
SECTION variables,BSS
<DS statements>
SECTION prog,CODE
<more code>
bad relocation information was being generated for
the continuation of the SECTION. This bug was left
over from version 1.03.
The following enhancements have been added:
- All console output except for error messages is now
sent to stderr - this enables stdout to be redirected,
producing an error file.
- Console (stderr) output has been modified to require
fewer lines on the screen.
- If an error occurs while expanding a macro or INCLUDE
file, the position of the call in each outer file is
given along with the position in the current (innermost)
file. Tracing continues until the outermost file (i.e.
the original source file) is reached.
Version 1.04 (Charlie Gibbs, October 21, 1987)
The following bugs in version 1.03 have been corrected:
- MOVE was being converted to MOVEQ regardless of
operand size - this conversion is legal only
for longword MOVEs.
- Modifications to version 1.03 caused bad relocatable
entries to be generated.
Version 1.03 (Charlie Gibbs, October 14, 1987)
The following bugs in version 1.02 have been corrected:
- The following situation was causing phase errors:
xdef label
bra label
.
<at least 128 bytes of object code>
.
label:
(The XDEF was fooling A68k into thinking that "label"
was defined within 128 bytes of the BRA instruction
on pass 1, although on pass 2 it knew better.
- If the first operand of an two-operand executable
instruction contained a character term containing a
left or right parenthesis, it would generate error
messages and be incorrectly evaluated.
- Labels that don't begin in column 1 (denoted by a
trailing colon) caused a Guru Meditation.
- Certain ADD and SUB instructions using PC-relative
addressing may cause phase errors. If the displacement
is in the range 1 to 8 inclusive, the instruction was
erroneously converted to ADDQ or SUBQ during pass 2.
The following enhancements have been added:
- The -z option has been added to display the
current source program line on stdout as it
is read, optionally over a given range.
This feature is provided for debugging purposes.
- Bcc, BSR, and DBcc to labels in other than the current
section is now supported. A 16-bit relocation entry
will be generated for each such reference.
- PC relative mode will be generated for backward
references to labels within the current CODE section
if legal for the current instruction. Forward
references will not be converted, since there is
no way of telling which section the label is in
during pass 1.
- The cumulative sizes of all sections by type (i.e.
CODE, DATA, and BSS) will be displayed at the end
of the listing file and the console display.
(Bruce Dawson)
- In the symbol table dump, section names will no
longer be indicated just as SECTION, but rather
as CODE, DATA, or BSS, depending on type.
Version 1.02 (Charlie Gibbs, September 9, 1987)
The following bugs in version 1.01 have been corrected:
- Duplicate labels were not being flagged.
- XDEF symbols were not being dumped to the
object code file when the -d option was set.
The following enhancements have been added:
- A header file is now supported. If the parameter
-h<filespec> is included on the command line, the
specified file will be included as if the source
file's first line was " include <filespec>".
The file specification may include a path name,
although the include path names given by the
-i parameter (if any) will also be searched.
- An equate file can now be produced. If the parameter
-e<filespec> is included on the command line, a file
will be written containing EQU statements for any
symbol whose value is absolute. If -e is specified
without <filespec>, the name of the file will be
formed in the same way as the list file, except with
an extension of ".equ". (Bruce Dawson)
The following changes have been made to existing logic:
- No symbol table dump will be produced unless the
-x (cross-reference) switch is set. Formerly a
symbol table dump was always produced, with only
the cross-reference portion optional.
Version 1.01 (Charlie Gibbs, August 20, 1987)
The following bugs in version 1.00 have been corrected:
- Long-word constants and storage areas were being
aligned on a double-word boundary. The only place
where double-word alignment is now forced is at a
break between SECTIONs, since the length of an
AmigaDOS hunk must be a multiple of 4 bytes.
(CNOP 0,4 can still be used if double-word
alignment is desired by the programmer.)
- If a label on an END statement or the first statement
of a SECTION was named in an XDEF statement, it would
not be written to the object code file. The latter
case includes both the label of a SECTION directive
and the label of the first executable instruction in
the absence of any SECTION directives (defaulting to
an unnamed CODE section). In the final case (default
unnamed CODE section), references to XREF symbols
in the first statement would also not be written
to the object code file.
- If the last statement in the source file was not
terminated with a newline character (premature EOF),
it was being ignored altogether.
- A register list as the source operand of a MOVE
instruction was not being flagged as an error.
(MOVE to a register list was being flagged, however.)
- MOVE from USP was generating incorrect code. Also,
MOVE from SR or CCR to an address register was
generating incorrect code rather than being flagged.
Version 1.00 (Charlie Gibbs, June 18, 1987) - initial release
SHAR_EOF
cat << \SHAR_EOF > A68k2do.txt
A68k - things to do as of January 10, 1989
*** BUGS ***
(There are no known bugs at this time.)
*** ENHANCEMENTS ***
Implement an ARexx interface to an editor (e.g. CED) for debugging.
Possibly commands could be read from a configuration file so that
A68k could be customized to any editor's commands and port name.
Improve the small code / small data option - study linker documentation!
Wild optimizations? (e.g. MOVE.W #0,D0 -> CLR.W D0)
Treat (An,Dn) as 0(An,Dn)? Or just leave for 68020 upgrade?
Add 68010/68020 support.
SHAR_EOF
cat << \SHAR_EOF > Makefile
# Simple makefile to compile and link the A68k Assembler.
# Created 23Jun87 by J.A. Lydiatt
#
OBJ= A68kmain.o Opcodes.o Operands.o Adirect.o A68kmisc.o\
Symtab.o Codegen.o wb_parse.o
SHARLIB1= A68k.doc makefile A68kdef.h A68kglb.h A68kmain.c Opcodes.c Operands.c\
Adirect.c A68kmisc.c Symtab.c Codegen.c wb_parse.c isspace.c
SRC= A68kmain.c Opcodes.c Operands.c Adirect.c A68kmisc.c\
Symtab.c Codegen.c wb_parse.c isspace.c
SHARLIB2= A68k.uue
.c.o:
cc +x3 -Z3000 -o $*.o $*.c
A68k: $(OBJ)
ln -o A68k $(OBJ) -lc
$(OBJ): A68kdef.h A68kglb.h
#
# Note: Manx's makefile seems to have a bug that forbids indirection
# such as "shar >lib a.c b.c c.c"
# however "make >lib" seems to work fine if you edit out the
# commands make echos as it proceeds through the makefile.
#
# Try make >ram:shardcp Archive
#
Archive:
shar $(SHARLIB1)
shar $(SHARLIB2)
Lint:
lint -iAztec:include Aztec:Stdlib.c Aztec:Defaults.c $(SRC)
SHAR_EOF
cat << \SHAR_EOF > Makefile.azt
# Simple makefile to compile and link the A68k Assembler.
# Created 23Jun87 by J.A. Lydiatt
#
OBJ= A68kmain.o Opcodes.o Operands.o Adirect.o A68kmisc.o\
Symtab.o Codegen.o wb_parse.o
SHARLIB1= A68k.doc makefile A68kdef.h A68kglb.h A68kmain.c Opcodes.c Operands.c\
Adirect.c A68kmisc.c Symtab.c Codegen.c wb_parse.c isspace.c
SRC= A68kmain.c Opcodes.c Operands.c Adirect.c A68kmisc.c\
Symtab.c Codegen.c wb_parse.c isspace.c
SHARLIB2= A68k.uue
.c.o:
cc +x3 -Z3000 -o $*.o $*.c
A68k: $(OBJ)
ln -t -o A68k $(OBJ) -lc
$(OBJ): A68kdef.h A68kglb.h
#
# Note: Manx's makefile seems to have a bug that forbids indirection
# such as "shar >lib a.c b.c c.c"
# however "make >lib" seems to work fine if you edit out the
# commands make echos as it proceeds through the makefile.
#
# Try make >ram:shardcp Archive
#
Archive:
shar $(SHARLIB1)
shar $(SHARLIB2)
Lint:
lint -iAztec:include Aztec:Stdlib.c Aztec:Defaults.c $(SRC)
SHAR_EOF
cat << \SHAR_EOF > Makefile.dbg
# Simple makefile to compile and link the A68k Assembler.
# Created 23Jun87 by J.A. Lydiatt
#
OBJ= A68kmain.o Opcodes.o Operands.o Adirect.o A68kmisc.o\
Symtab.o Codegen.o wb_parse.o isspace.o
SHARLIB1= A68k.doc makefile A68kdef.h A68kglb.h A68kmain.c Opcodes.c Operands.c\
Adirect.c A68kmisc.c Symtab.c Codegen.c wb_parse.c isspace.c
SRC= A68kmain.c Opcodes.c Operands.c Adirect.c A68kmisc.c\
Symtab.c Codegen.c wb_parse.c isspace.c
SHARLIB2= A68k.uue
.c.o:
cc -n -Z3000 -o $*.o $*.c
A68k: $(OBJ)
ln -g -o A68k $(OBJ) -lc
$(OBJ): A68kdef.h A68kglb.h
#
# Note: Manx's makefile seems to have a bug that forbids indirection
# such as "shar >lib a.c b.c c.c"
# however "make >lib" seems to work fine if you edit out the
# commands make echos as it proceeds through the makefile.
#
# Try make >ram:shardcp Archive
#
Archive:
shar $(SHARLIB1)
shar $(SHARLIB2)
Lint:
lint -iAztec:include Aztec:Stdlib.c Aztec:Defaults.c $(SRC)
SHAR_EOF
cat << \SHAR_EOF > Makefile.pdc
# Simple makefile to compile and link the A68k Assembler.
# Created 23Jun87 by J.A. Lydiatt
#
OBJ= A68kmain.o Opcodes.o Operands.o Adirect.o A68kmisc.o\
Symtab.o Codegen.o wb_parse.o isspace.o
SHARLIB1= A68k.doc makefile A68kdef.h A68kglb.h A68kmain.c Opcodes.c Operands.c\
Adirect.c A68kmisc.c Symtab.c Codegen.c wb_parse.c isspace.c
SRC= A68kmain.c Opcodes.c Operands.c Adirect.c A68kmisc.c\
Symtab.c Codegen.c wb_parse.c isspace.c
SHARLIB2= A68k.uue
.c.o:
cc -P -qvd0: -c $*.c
A68k: $(OBJ)
cc -o A68k $(OBJ)
$(OBJ): A68kdef.h A68kglb.h
#
# Note: Manx's makefile seems to have a bug that forbids indirection
# such as "shar >lib a.c b.c c.c"
# however "make >lib" seems to work fine if you edit out the
# commands make echos as it proceeds through the makefile.
#
# Try make >ram:shardcp Archive
#
Archive:
shar $(SHARLIB1)
shar $(SHARLIB2)
Lint:
lint -iAztec:include Aztec:Stdlib.c Aztec:Defaults.c $(SRC)
SHAR_EOF
cat << \SHAR_EOF > wb_parse.c
_wb_parse(){}
SHAR_EOF
# End of shell archive
exit 0
--
Bob Page, U of Lowell CS Dept. page@swan.ulowell.edu ulowell!page
Have five nice days.